<?php
namespace Model;

use Core\Exception\BusinessException;
use Core\Helper\CommonHelper;
use Zend\Db\Adapter\Adapter;
use Core\Session\AdminSessionHelper;
use Zend\Db\Sql\Expression;
use Zend\Db\Sql\Predicate\Like;
use Zend\Db\Sql\Predicate\Operator;
use Zend\Db\Sql\Select;
use Zend\InputFilter\InputFilter;

class CategoryTable extends AbstractTable implements LanguageAwareInterface
{

    /**
     * @var string
     */
    private $_lang;

    /**
     * @param $id
     * @return Category
     */

    public function getCategory($id){
       return $this->getById($id);
    }

    /**
     * @param $name
     * @return Category
     */
    public function getCategoryByName($name)
    {
        return $this->getTableGateway()->select(array(
            'name'=>$name,
            'lang'=>$this->_lang
        ))->current();
    }

    /**
     * @param $code
     * @return Category
     */
    public function getCategoryByCode($code)
    {
        return $this->getTableGateway()->select(array(
            'code'=>$code,
            'lang'=>$this->_lang
        ))->current();

    }

    /**
     * @return InputFilter
     */
    public function getInputFilter()
    {
        $filter = new InputFilter();

        return $filter;
    }

    public function searchCategory($isPaging, $offset, $rowPerPage, $orderArr = array('name'), $searchOption){
        $groupId = $searchOption["groupCode"];
        if(!$groupId) throw new BusinessException("groupCode null!");
        $category_Item = $this->getCategory($groupId);
        $group_code = $category_Item->group_code;
        $select = $this->getDbSqlSelect();
        $select->join(array("parent"=>"category"),new Expression('1=1') , array())
            ->where('category.lft BETWEEN parent.lft AND parent.rgt')
            ->where(array('parent.id'=>$groupId))
            ->where(array('category.group_code'=>$group_code))
            ->where(array('category.lang'=>$this->_lang))
            ->order('category.lft');
        return $this->executeSelectForArray($select);
    }

    /**
     * @return \Zend\Db\ResultSet\ResultSet
     */
    public function getAllActiveCategory(){
        return $this->getTableGateway()->select(array('active'=>1,'lang'=>$this->_lang));
    }


    public function getAllCategory()
    {
        $select = $this->getDbSqlSelect();
        $select->where(array('lang'=>$this->_lang))
        ->order(array('group_code','lft'));
        return $this->executeSelectForArray($select);
    }

    public function removeCategory($id)
    {
        $category_Item = $this->getCategory($id);
        //if iam a child
        if($category_Item->lft == $category_Item->rgt - 1){
            $this->reorderTreeOnDelete($category_Item);
        }else{
            throw new BusinessException("Không được xóa nhóm có nhóm con!");
        }
        $this->delete($id);
    }

    private function reorderTreeOnDelete($categoryItem){
        $group_code = $categoryItem->group_code;
        $this->getTableGateway()->update(array('rgt'=>new Expression('rgt - 2')),
        array('rgt > '.$categoryItem->rgt, 'group_code'=>$group_code, 'lang'=>$this->_lang));

        $this->getTableGateway()->update(array('lft'=>new Expression('lft - 2')),
            array('lft > '.$categoryItem->rgt, 'group_code'=>$group_code, 'lang'=>$this->_lang));
    }

    public function getLang()
    {
        return $this->_lang;
    }

    public function setLang($lang)
    {
        $this->_lang = $lang;
    }

    public function addCategory($data)
    {
        $parentId = $data["parentId"];
        $parentItem = $this->getCategory($parentId);
        $tmpData = $data;

        if($data["name"]){
            $tmpData["alias"] = CommonHelper::vietnameseToASCII($data["name"]);
        }

        $tmpData["group_code"] = $parentItem->group_code;
        $tmpData["lft"] = $parentItem->rgt;
        $tmpData["rgt"] = $parentItem->rgt + 1;
        $this->reorderTree(  $parentItem->group_code, $parentItem->rgt - 1);
        unset($tmpData["parentId"]);
        return  $this->insert($tmpData);
    }

    private function reorderTree($group_code, $lastRight){
        $this->getTableGateway()->update(array('rgt'=>new Expression('rgt + 2')),
            array('rgt > '.$lastRight, 'group_code'=>$group_code, 'lang'=>$this->_lang));

        $this->getTableGateway()->update(array('lft'=>new Expression('lft + 2')),
            array('lft > '.$lastRight, 'group_code'=>$group_code, 'lang'=>$this->_lang));
    }

    public function updateCategory($data)
    {
        $tmp = $data;
        if($data["name"]){
            $tmp["alias"] = CommonHelper::vietnameseToASCII($data["name"]);
        }

        $categoryItem = $this->getCategory($data['id']);
        if($categoryItem->modifiable == 0)
            throw new BusinessException("Không thể sửa category này. Vui lòng liên hệ admin.");
        $this->update($tmp, $data['id']);
    }

    public function getAllCategoryGroup()
    {
        return $this->getTableGateway()->select(array('lft'=>1, 'lang'=>$this->_lang));

    }



    public function getAllCategoriesByGroupCode($code)
    {

        if(!$code) throw new BusinessException("groupCode null!");
        $category_Item = $this->getRootCategory($code);
        $select = $this->getDbSqlSelect();
        $select->join(array("parent"=>"category"),new Expression('1=1') , array())
            ->where('category.lft BETWEEN parent.lft AND parent.rgt')
            ->where(array('parent.id'=>$category_Item->id))
            ->where(array('category.group_code'=>$code))
            ->where(array('category.lang'=>$this->_lang))
            ->order('category.lft');


        return $this->executeSelectForArray($select);

    }



    public function getAllParent($catId)
    {
        $category_Item = $this->getCategory($catId);
        return $this->getTableGateway()->select(array(
            'group_code'=>$category_Item->group_code,
            'lft < '.$category_Item->lft,
            'rgt > '.$category_Item->rgt,
            'lang'=>$this->_lang
        ));
    }

    public function getAllChildren($catId)
    {
        $category_Item = $this->getCategory($catId);
        return $this->getTableGateway()->select(array(
            'group_code'=>$category_Item->group_code,
            'lft > '.$category_Item->lft,
            'rgt < '.$category_Item->rgt,
            'lang'=>$this->_lang
        ));
    }

    public function getAllCategoriesByParentCode($code)
    {

        if(!$code) throw new BusinessException("parentCode null!");
        $category_Item = $this->getCategoryByCode($code);
        $select = $this->getDbSqlSelect();

        $select->join(array("parent"=>"category"),new Expression('1=1') , array())
            ->where('category.lft BETWEEN parent.lft AND parent.rgt')
            ->where(array('parent.id'=>$category_Item->id))
            ->where(array('category.group_code'=>$code))
            ->where(array('category.lang'=>$this->_lang))
            ->order('category.lft');


        return $this->executeSelectForArray($select);
    }

    public function getCategoryByAlias($categoryAlias)
    {
        return $this->getTableGateway()->select(array(
            'alias'=>$categoryAlias,
            'lang'=>$this->_lang
        ))->current();
    }

    public function getCategoryAsKendoDataSource($groupCode)
    {

        $rows = $this->getAllCategoriesByGroupCode($groupCode);
        return $this->getTreeKendoDatasource($rows);
    }

    private function getTreeKendoDatasource($rows){
        $right = array();
        $result = array();

        foreach ($rows as $anItem) {
            $item = $anItem->toArray();
            $item["text"] = $item["name"];

            if(count($right)>0){
                while ($right[count($right)-1]['rgt']<$item['rgt']) {
                    array_pop($right);
                }
            }
            if($item['lft'] < $item['rgt'] -1){

                $item["items"] = array();
            }
            if(count($right)>0){
                $latestHasChildren = &$this->findLatestHasChildren($result[(count($result)-1)], $right[count($right)-1]);

                $latestHasChildren["items"][] =  $item;

            }else{
                call_user_func_array("array_push", array(&$result,&$item));
            }

            call_user_func_array("array_push", array(&$right,&$item));

        }
        return $result;
    }

    private function &findLatestHasChildren(&$arr, $sample){

        if(array_key_exists("items",$arr)){
            if(count($arr["items"]) == 0 || !array_key_exists("items",$arr["items"][count($arr["items"]) -1]) ){
                return $arr;
            }elseif(array_key_exists("items",$arr["items"][count($arr["items"]) -1])
                && $arr["items"][count($arr["items"]) -1]["rgt"] < $sample["rgt"]){
                return $arr;
            }
            else {
                return $this->findLatestHasChildren($arr["items"][count($arr["items"]) -1],$sample);
            }
        }
        else{
            return $arr;
        }
    }

    public function getCategoryByCodeInGroup($groupCode, $code)
    {
        return $this->getTableGateway()->select(array(
            'code'=>$code,
            'group_code'=>$groupCode,
            'lang'=>$this->_lang,
        ))->current();
    }

    /**
     * @param $groupCode
     * @return Category
     */
    public function getRootCategory($groupCode){
        return $this->getTableGateway()->select(array(
            'group_code'=>$groupCode,
            'lft'=>1,
            'lang'=>$this->_lang
        ))->current();
    }
    public function getAll(){
        return $this->getTableGateway()->select(array('lang'=>$this->_lang));
    }
}